package mnttab;

#########################################################################
# On many UNIX's this will look in /etc/mnttab, though on Linux it will	#
# instead use the /etc/mtab file...					#
# On Solaris we only look at disk sets, so these are expected to have	#
# paths such as the following:						#
# /dev/md/DISKSET/dsk/volume						#
#########################################################################

use File::Basename;
use Data::Dumper;
use Config;
use Sys::Hostname;
use strict;
use Carp qw(croak cluck);

sub new {
my $proto=shift;
my $class=ref($proto) || $proto;
my $self={};
	
	my $fn;
	if($Config{'osname'} eq "freebsd") {
		$fn="/sbin/mount|";
	} elsif(-f "/etc/mtab") {
		$fn="/etc/mtab";
	} else {
		$fn="/etc/mnttab";
	}
	if($fn !~ /\|/ && ! -r $fn) {
		cluck("The '$fn' file is not readable!");
	}

	$self->{FILE}=$fn;
	_load_mnttab($self);
	bless($self,$class);
	return $self;
}

sub _load_mnttab($) {
my $self=shift;
my @L=();
my ($fd,$cline,$cvg,$clv);

	if(!open($fd,$self->{FILE})) {
		cluck("Not able to open '$self->{FILE}'!");
	}
	$self->{FS}={};
	$self->{LV}={};

	my ($lv,$vg);
	my $linenum=0;
	my $freebsd=0;
	$freebsd=1 if $Config{'osname'} eq "freebsd";
	while(<$fd>) {
		$linenum++;
		chomp;
		my @F=split;
		if($freebsd) {
			# format fields in required order
			$self->{BYMNT}->{$F[2]}=$F[0];
			my $x=join("",@F[3 .. $#F]); $x =~ s/\(//; $x =~ s/\)//; $x =~ s/\s+//g;
			my @F2=split(/,/,$x); my $type=$F2[0];
			$F[1]=$F[2];
			$F[2]=$type;
			$F[3]=join(",",@F2[1 .. $#F2]);
		}
		if($F[0] =~ /:/) {
			$F[0]="NFS:$F[0]";
		}
		next if ($F[2] ne "zfs" && ($F[0] !~ /^\/dev/ && $F[0] !~ /^NFS:/));
		$self->{BYMNT}->{$F[1]}=$F[0];
		
		#########################################################
		# The format of the mount device must be parsed - 	#
		# abort if not recognised.				#
		#########################################################

		my $dev=$F[0];
		my $blockdev=$dev;
		undef $vg;
		undef $lv;
		#########################################################
		# Handle VxVM device configuration first...		#
		#########################################################
		if($F[2] eq "zfs") {
			($vg,$lv)=($dev =~ /^(.*?)\/(.*)/);
		} elsif($dev =~ /^\/dev\/vx\/dsk\//) {
			$dev =~ s/^\/dev\/vx\/dsk\///;
			($vg,$lv)=split(/\//,$dev);
		} elsif($dev =~ /^\/dev\/md\/dsk\/([a-z0-9A-Z_\-]+)$/) {
			($vg,$lv)=("NA",$1);
		} elsif($dev =~ /^\/dev\/md\/(.*)\/dsk\/(.*)$/) {
			($vg,$lv)=($1,$2);
		} elsif($dev =~ /^\/dev\/mapper\/([a-z0-9A-Z_\-]+)-([a-z0-9A-Z_\-]+)$/) {
			($vg,$lv)=($1,$2);
		} elsif($dev =~ /^\/dev\/([a-z0-9A-Z_\-]+)\/([a-z0-9A-Z_\-]+)$/) {
			($vg,$lv)=($1,$2);
		} elsif($dev =~ /:/) {
			($vg,$lv)=("NFS",$dev);
		} elsif($dev =~ /^\/dev\/(drbd.*)/) {
			($vg,$lv)=("NA",$1);
		}
		if(!defined($vg) || !defined($lv)) {
			next;
		}
		$self->{FS}->{$F[1]}={};
		$self->{FS}->{$F[1]}->{VG}=$vg;
		$self->{FS}->{$F[1]}->{FS}=$F[1];
		$self->{FS}->{$F[1]}->{LV}=$lv;
		if($vg eq "NFS") {
			$self->{FS}->{$F[1]}->{BLOCKDEV}="";
		} else {
			$self->{FS}->{$F[1]}->{BLOCKDEV}=$blockdev;
		}
		$self->{FS}->{$F[1]}->{TYPE}=$F[2];
		$self->{FS}->{$F[1]}->{OPTS}=$F[3];
		if($vg eq "NFS") {
			$self->{LV}->{"$lv"}={};
			$self->{LV}->{"$lv"}->{FS}=$F[1];
		} else {
			$self->{LV}->{"$vg:$lv"}={};
			$self->{LV}->{"$vg:$lv"}->{FS}=$F[1];
		}
	}
	close($fd);
}

sub is_mounted($$) {
my ($self,$fs)=@_;

	#################################################################
	# Return 1 if file system mounted, 0 if not.			#
	#################################################################
	if(exists($self->{FS}->{$fs})) {
		return 1;
	}
	return 0;
}

sub get_from_vglv($$$) {
my ($self,$vg,$lv)=@_;

	if($vg eq "NFS" && $lv =~ /^NFS:/) {
		if(exists($self->{LV}->{$lv})) {
			my $r=$self->{LV}->{$lv};
			my %h=%{$self->{FS}->{$r->{FS}}};
			return {%h};
		}
	}
	if(!exists($self->{LV}->{"$vg:$lv"})) {
		return undef;
	}
	my $r=$self->{LV}->{"$vg:$lv"};
	my %h=%{$self->{FS}->{$r->{FS}}};
	return {%h};
}

sub get_from_fs($$) {
my ($self,$fs)=@_;

	if(!exists($self->{FS}->{$fs})) {
		return undef;
	}
	my %h=%{$self->{FS}->{$fs}};
	return {%h};
}

sub mount_dev($$) {
my ($self,$fs)=@_;

	if(!exists($self->{BYMNT}->{$fs})) {
		return undef;
	}
	return $self->{BYMNT}->{$fs};
}

1;

